package com.example.lotterysystem.service.impl;

import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JacksonUtil;
import com.example.lotterysystem.common.utils.RedisUtil;
import com.example.lotterysystem.controller.param.DrawPrizeParam;
import com.example.lotterysystem.controller.param.ShowWinningRecordsParam;
import com.example.lotterysystem.dao.dataobject.*;
import com.example.lotterysystem.dao.mapper.*;
import com.example.lotterysystem.service.DrawPrizeService;
import com.example.lotterysystem.service.dto.WinningRecordDTO;
import com.example.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.example.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.example.lotterysystem.service.enums.ActivityStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.example.lotterysystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static com.example.lotterysystem.common.config.DirectRabbitConfig.ROUTING;

@Service
public class DrawPrizeServiceImpl implements DrawPrizeService {

    private static final Logger logger = LoggerFactory.getLogger(DrawPrizeServiceImpl.class);

    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";
    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;
    @Autowired
    private RedisUtil redisUtil;


    @Override
    public void drawPrize(DrawPrizeParam param) {
        Map<String, String> map = new HashMap<>();
        map.put("messageId", String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING, map);
        logger.info("mq消息发送成功：map={}", JacksonUtil.writeValueAsString(map));
    }

    @Override
    public boolean checkDrawPrizeParam(DrawPrizeParam param) {
        ActivityDo activityDo = activityMapper.selectById(param.getActivityId());
        ActivityPrizeDo activityPrizeDo = activityPrizeMapper.selectByAPId(param.getActivityId(),
                param.getPrizeId());

        // 活动或奖品是否存在
        if(activityDo == null || activityPrizeDo == null){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY.getMessage());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
        }

        // 活动是否有效
        if(activityDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_COMPLETED.getMessage());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_COMPLETED);
        }

        // 奖品是否有效
        if (activityPrizeDo.getStatus()
                .equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name())) {
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMessage());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED);
        }
        // 中奖者人数是否和设置奖品数量一致 3 2
        if (activityPrizeDo.getPrizeAmount() != param.getWinnerList().size()) {
            logger.info("校验抽奖请求失败！失败原因：{}",
                    ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR.getMessage());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR);
        }
        return true;
    }

    @Override
    public List<WinningRecordDo> saveWinnerRecords(DrawPrizeParam param) {
        // 查询相关信息：活动、人员、奖品、活动关联奖品
        ActivityDo activityDo = activityMapper.selectById(param.getActivityId());
        List<UserDo> userDoList = userMapper.batchSelectByIds(param.getWinnerList().stream()
                .map(DrawPrizeParam.Winner::getUserId)
                .collect(Collectors.toList()));
        PrizeDo prizeDo = prizeMapper.selectById(param.getPrizeId());
        ActivityPrizeDo activityPrizeDO =
                activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());

        // 构造中奖者记录，保存
        List<WinningRecordDo> winningRecordDoList = userDoList.stream()
                .map(userDo -> {
                    WinningRecordDo winningRecordDo = new WinningRecordDo();
                    winningRecordDo.setActivityId(activityDo.getId());
                    winningRecordDo.setActivityName(activityDo.getActivityName());
                    winningRecordDo.setPrizeId(prizeDo.getId());
                    winningRecordDo.setPrizeName(prizeDo.getName());
                    winningRecordDo.setPrizeTier(activityPrizeDO.getPrizeTiers());
                    winningRecordDo.setWinnerId(userDo.getId());
                    winningRecordDo.setWinnerName(userDo.getUserName());
                    winningRecordDo.setWinnerEmail(userDo.getEmail());
                    winningRecordDo.setWinnerPhoneNumber(userDo.getPhoneNumber());
                    winningRecordDo.setWinningTime(param.getWinningTime());
                    return winningRecordDo;
                }).collect(Collectors.toList());
        winningRecordMapper.batchInsert(winningRecordDoList);

        //两个维度缓存中奖者记录

        // 缓存中奖者记录
        // 1、缓存奖品维度中奖记录(WinningRecord_activityId_prizeId, winningRecordDOList（奖品维度的中奖名单）)
        cacheWinningRecords(param.getActivityId() + "_" + param.getPrizeId()
                , winningRecordDoList , WINNING_RECORDS_TIMEOUT);

        // 2、缓存活动维度中奖记录(WinningRecord_activityId, winningRecordDOList(活动维度的中奖名单))
        // 当活动已完成再去存放活动维度中奖记录
        if(activityDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            List<WinningRecordDo> allList = winningRecordMapper.selectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),
                    allList , WINNING_RECORDS_TIMEOUT);
        }
        return winningRecordDoList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(activityId == null){
            logger.info("要删除的奖品关联的activityId为空");
            return;
        }
        winningRecordMapper.deleteRecords(activityId , prizeId);

        //删除奖品维度中的获奖记录
        if(prizeId != null){
            deleteWinningRecords(activityId + "_" + prizeId);
        }

        //删除活动维度的获奖纪录
        deleteWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getRecords(ShowWinningRecordsParam param) {
        String key = null == param.getPrizeId() ? String.valueOf(param.getActivityId()) :
                param.getActivityId() + "_" + param.getPrizeId();
        List<WinningRecordDo> winningRecordDoList = getWinningRecords(key);
        if(!CollectionUtils.isEmpty(winningRecordDoList)){
             return convertToWinningRecordDTOList(winningRecordDoList);
        }

        winningRecordDoList = winningRecordMapper.selectByActivityIdOrPrizeId(
                param.getActivityId(), param.getPrizeId());

        // 存放记录到redis
        if (CollectionUtils.isEmpty(winningRecordDoList)) {
            logger.info("查询的中奖记录为空！param:{}",
                    JacksonUtil.writeValueAsString(param));
            return Arrays.asList();
        }
        cacheWinningRecords(key, winningRecordDoList, WINNING_RECORDS_TIMEOUT);
        return convertToWinningRecordDTOList(winningRecordDoList);
    }

    private List<WinningRecordDTO> convertToWinningRecordDTOList(
            List<WinningRecordDo> winningRecordDOList) {
        if (CollectionUtils.isEmpty(winningRecordDOList)) {
            return Arrays.asList();
        }
        return winningRecordDOList.stream()
                .map(winningRecordDO -> {
                    WinningRecordDTO winningRecordDTO = new WinningRecordDTO();
                    winningRecordDTO.setWinnerId(winningRecordDO.getWinnerId());
                    winningRecordDTO.setWinnerName(winningRecordDO.getWinnerName());
                    winningRecordDTO.setPrizeName(winningRecordDO.getPrizeName());
                    winningRecordDTO.setPrizeTier(
                            ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()));
                    winningRecordDTO.setWinningTime(winningRecordDO.getWinningTime());
                    return winningRecordDTO;
                }).collect(Collectors.toList());
    }

    private void deleteWinningRecords(String key) {
        try {
            if (redisUtil.hasKey(WINNING_RECORDS_PREFIX + key)) {
                // 存在再删除
                redisUtil.del(WINNING_RECORDS_PREFIX + key);
            }
        }catch (Exception e){
            logger.error("删除中奖记录缓存异常，key:{}", key);
        }
    }

    private void cacheWinningRecords(String key,
                                     List<WinningRecordDo> winningRecordDoList,
                                     Long winningRecordsTimeout) {
        String str = "";
        try {
            if (!StringUtils.hasText(key) || CollectionUtils.isEmpty(winningRecordDoList)) {
                logger.warn("要缓存的内容为空！key:{}, value:{}",
                        key, JacksonUtil.writeValueAsString(winningRecordDoList));
                return;
            }
            str = JacksonUtil.writeValueAsString(winningRecordDoList);
            redisUtil.set(WINNING_RECORDS_PREFIX + key, str, winningRecordsTimeout);
        } catch (Exception e) {
            logger.error("缓存中奖记录异常！key:{}, value:{}", WINNING_RECORDS_PREFIX + key, str);
        }
    }

    private List<WinningRecordDo> getWinningRecords(String key){

        try {
            if(!StringUtils.hasText(key)){
                logger.warn("要从缓存中查询中奖记录的key为空！");
                return Arrays.asList();
            }
            String str = redisUtil.get(WINNING_RECORDS_PREFIX + key);
            if (!StringUtils.hasText(str)) {
                return Arrays.asList();
            }
            return JacksonUtil.readListValue(str , WinningRecordDo.class);
        }catch (Exception e){
            logger.error("从缓存中查询中奖记录异常！key:{}", WINNING_RECORDS_PREFIX + key);
            return Arrays.asList();
        }

    }
}












